@classmethod, @staticmethod, and @property¶
A decorator is a special kind of function that either takes a function
and returns a function, or takes a class and returns a class.
The @ symbol is just syntactic sugar that allows you to decorate
something in a way that’s easy to read.
The decorators
@classmethod,
@staticmethod and
@property
are used on functions defined within classes.
class MyClass(object):
def __init__(self):
self._some_property = "properties are nice"
self._some_other_property = "VERY nice"
def normal_method(*args,**kwargs):
print("calling normal_method({0},{1})".format(args,kwargs))
@classmethod
def class_method(*args,**kwargs):
print("calling class_method({0},{1})".format(args,kwargs))
@staticmethod
def static_method(*args,**kwargs):
print("calling static_method({0},{1})".format(args,kwargs))
@property
def some_property(self,*args,**kwargs):
print("calling some_property getter({0},{1},{2})".format(self,args,kwargs))
return self._some_property
@some_property.setter
def some_property(self,*args,**kwargs):
print("calling some_property setter({0},{1},{2})".format(self,args,kwargs))
self._some_property = args[0]
@property
def some_other_property(self,*args,**kwargs):
print("calling some_other_property getter({0},{1},{2})".format(self,args,kwargs))
return self._some_other_property
o = MyClass()
# undecorated methods work like normal, they get the current instance (self) as the first argument
Normal methods¶
o.normal_method
# <bound method MyClass.normal_method of <__main__.MyClass instance at 0x7fdd2537ea28>>
o.normal_method()
# calling normal_method((<__main__.MyClass object at 0x00000000039C8208>,),{})
o.normal_method(1,2,x=3,y=4)
# calling normal_method((<__main__.MyClass object at 0x00000000039C8208>, 1, 2),{'x': 3, 'y': 4})
Class methods¶
Always get the class as the first argument
o.class_method
# <bound method classobj.class_method of <class __main__.MyClass at 0x7fdd2536a390>>
o.class_method()
# calling class_method((<class '__main__.MyClass'>,),{})
o.class_method(1,2,x=3,y=4)
# calling class_method((<class '__main__.MyClass'>, 1, 2),{'x': 3, 'y': 4})
Static methods¶
Have no arguments except the ones you pass in when you call them
o.static_method
# <function static_method at 0x7fdd25375848>
o.static_method()
# calling static_method((),{})
o.static_method(1,2,x=3,y=4)
# calling static_method((1, 2),{'x': 3, 'y': 4})
Properties¶
Are a way of implementing getters and setters.
It’s an error to explicitly call them “read only” attributes
can be specified by creating a getter without a setter
(as in some_other_property)
o.some_property
# calling some_property getter(<__main__.MyClass object at 0x00000000039E8EB8>,(),{})
# 'properties are nice'
o.some_property()
# calling some_property getter(<__main__.MyClass object at 0x00000000039E8EB8>,(),{})
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# TypeError: 'str' object is not callable
o.some_other_property
# calling some_other_property getter(<__main__.MyClass instance at 0x7fb2b70877e8>,(),{})
# 'VERY nice'
o.some_other_property()
# calling some_other_property getter(<__main__.MyClass instance at 0x7fb2b70877e8>,(),{})
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# TypeError: 'str' object is not callable
o.some_property = "groovy"
# calling some_property setter(<__main__.MyClass object at 0x7fb2b7077890>,('groovy',),{})
o.some_property
# calling some_property getter(<__main__.MyClass object at 0x7fb2b7077890>,(),{})
# 'groovy'
o.some_other_property = "very groovy"
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# AttributeError: can't set attribute
o.some_other_property
# calling some_other_property getter(<__main__.MyClass object at 0x7fb2b7077890>,(),{})
# 'VERY nice'